--[[ PeJuGe(2010) . S.O.M.A 1.0 ~ System of Matrix
     DONT REMOVE THE CREDITS
     Exclusive For www.otserv.com.br
     More Info: http://forums.otserv.com.br/showthread.php?p=1037456#post1037456
     + matrix.correct(m)
       * Returnes true for correct matrix or false.
     + matrix.sqr(m)
       * Returns true for square matrix or false.
     + matrix.lines(m)
       * Returns the number of lines.
     + matrix.columns(m)
       * Returns the number of columns.
     + matrix.addline(l1, l2)
       * Returns the added lines.
     + matrix.column(m, n)
       * Returns the selected column.
     + matrix.reverse(m)
       * Returns reversed matrix.
     + matrix.addline(l1, l2)
       * Returns the sun of l1 and l2.
     + matrix.addcolunm(m1, n1, m2, n2)
       * Returns the sun of columns n1 from m1 and n2 from m2.
     + matrix.add
       * Returns the sun of matrixes.
     + matrix.mulline(l1, l2)
       * Returns the multiplication of l1 and l2.
     + matrix.mul(m1, m2)
       * Returns multiplicated matrixes.
     + matrix.concat(m)
       * Returns concated matrix.
     + matrix.det(m)
       * Returns the det of matrix (At moment alone smaller or equal than 3).
]]--

matrix = {}

function matrix.correct(m, r)
   r = r or 1
   return #m >= r and #m[r] == #m[1] and matrix.correct(m, r + 1) or #m < r
end

function matrix.sqr(m)
   return matrix.correct(m) and #m == #m[1] and #m
end

function matrix.lines(m)
   return matrix.correct(m) and #m
end

function matrix.columns(m)
   return matrix.correct(m) and #m[1]
end

function matrix.column(m, n, r)
   r = r or {}
   r[#r + 1] = m[#r + 1][n]
   return #r == #m and r or matrix.column(m, n, r)
end

function matrix.reverse(m, r)
   r = r or {}
   r[#r + 1] = matrix.column(m, #r + 1)
   return #r == #m[1] and r or matrix.reverse(m, r)
end

function matrix.addline(l1, l2, r)
   r = r or {}
   r[#r + 1] = l1[#r + 1] + l2[#r + 1]
   return #l1 == #r and r or matrix.addline(l1, l2, r)
end

function matrix.addcolumn(m1, n1, m2, n2, r)
   return matrix.addline(matrix.column(m1, n1), matrix.column(m2, n2))
end

function matrix.add(m1, m2, r)
   r = r or {}
   r[#r + 1] = matrix.addline(m1[#r + 1], m2[#r + 1])
   return #m1 == #r and r or matrix.sun(m1, m2, r)
end

function matrix.mulline(l1, l2, r)
   r = r or {0, 0}
   r[1], r[2] = r[1] + l1[r[2] + 1] * l2[r[2] + 1], r[2] + 1
   return r[2] == #l1 and r[1] or matrix.mulline(l1, l2, r)
end

function matrix.mul(m1, m2, r, n)
   m2, r, n = not r and matrix.reverse(m2) or m2, r or {}, n or 1
   r[#r + 1] = n ~= #r and {} or nil
   r[#r][#r[#r] + 1] = matrix.mulline(m1[#r], m2[#r[#r] + 1])
   n = #m2 == #r[#r] and n + 1 or n
   return n > #m1 and r or matrix.mul(m1, m2, r, n)
end

function matrix.concat(m, r)
   r = r or {}
   r[#r + 1] = table.concat(m[#r + 1], " ")
   return #m == #r and table.concat(r, "\n") or matrix.concat(m, r)
end

function matrix.det(m)
   sqr = matrix.sqr(m)
   return matrix.sqr and (
          sqr == 1 and m[1][1] or
          sqr == 2 and m[1][1] * m[2][2] - m[1][2] * m[2][1] or
          sqr == 3 and m[1][1] * m[2][2] * m[3][3] + m[1][2] * m[2][3] * m[3][1] + m[1][3] * m[2][1] * m[3][2] - (m[3][1] * m[2][2] * m[1][3] + m[3][2] * m[2][3] * m[1][1] + m[3][3] * m[2][1] * m[1][2]) or
          false) or false
end
